package com.panopset.sf;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import com.panopset.Alert;
import com.panopset.Util;
import com.panopset.compat.Strings;
import com.panopset.refactorsf.LookAndFeel;
import com.panopset.refactorsf.Validator;

public abstract class PanField extends WindocField {

	protected final String title;
	
	private final String tip;

	public PanField(final Windoc windoc, final String borderTitle,
			final String defaultValue) {
		this(windoc, 10, borderTitle, defaultValue, "", "");
	}

	public PanField(final Windoc windoc, final Integer columns,
			final String borderTitle, final String toolTipText,
			final String defaultValue, String key) {
		super(windoc, defaultValue, key);
		title = borderTitle;
		tip = toolTipText;
		getPanel().setToolTipText(toolTipText);
		getTF().setToolTipText(toolTipText);
		getTF().setColumns(columns);
	}
	
	public String getText() {
		return getGuiValue();
	}

	@Override
	protected void setGuiValue(final String val) {
		getTF().setText(val);
	}

	@Override
	protected String getGuiValue() {
		return getTF().getText();
	}
	
	private JTextField tf;

	public JTextField getTF() {
		if (tf == null) {
			tf = new JTextField();
			FontManager.getInstance().register(tf,
					FontManager.FontType.monospace);
			String s = getPanValue();
			if (Strings.isPopulated(s)) {
				tf.setText(s);
			}
			tf.addFocusListener(new FocusListener() {

				@Override
				public void focusGained(FocusEvent e) {
					// TODO Auto-generated method stub

				}

				@Override
				public void focusLost(FocusEvent e) {
			        reportChange();
					//saveValue(((JTextField) e.getComponent()).getText());
				}

			});
			tf.addKeyListener(new KeyAdapter() {
			    @Override
			    public final void keyPressed(final KeyEvent e) {
			        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			            reportChange();
			        }
			    }
			});
		}
		return tf;
	}
	
	/**
	 * As part of creating this panel, make sure you add the JComponent returned
	 * by getTF().
	 * 
	 * @param p
	 *            Panel to populate.
	 */
	protected abstract void populatePanel(JPanel panel);

	private JPanel panel;

	public JPanel getPanel() {
		if (panel == null) {
			panel = new JPanel();
			TitledBorder tb = new TitledBorder(title);
			tb.setTitleColor(LookAndFeel.Colors.FG_COLOR.getColor());
			FontManager.getInstance().register(tb,
					FontManager.FontType.borderTitle);
			panel.setBorder(tb);
			populatePanel(panel);
		}
		return panel;
	}

	public Windoc getDoc() {
		return wd;
	}

	public String getValue() {
		return getTF().getText();
	}

    /**
     * Validators.
     */
    private final List<Validator> validators = new ArrayList<Validator>();

    /**
     * This won't do anything unless a validator has been added.
     *
     * @param value
     *            Value to validate.
     * @return Message.
     */
    protected final String validate(final String value) {
        String lastMessage = null;
        for (Validator validator : validators) {
            String msg = validator.validate(value);
            if (Strings.isPopulated(msg)) {
                lastMessage = msg;
            }
        }
        return lastMessage;
    }

    /**
     * Add a Validator to this field.
     *
     * @param validator
     *            Validator.
     */
    public final void addValidator(final Validator validator) {
        validators.add(validator);
    }

    public final boolean isValid(final String value) {
        String msg = validate(value);
        if (Strings.isPopulated(msg)) {
            dspHighlightedMsg(msg);
        } else {
            return true;
        }
        return false;
    }

    /**
     * Override to respond to a valid value entered by the user.
     *
     * @param value
     *            New value.
     */
    protected void update(final String value) {

    }

    /**
     * Report change.
     */
    final void reportChange() {
        resetHighlighting();
        String msg = validate(getTF().getText());
        if (Strings.isPopulated(msg)) {
            dspHighlightedMsg(msg);
        } else {
            resetHighlighting();
        }
    }

    /**
     * Display highlighted message.
     *
     * @param msg
     *            Message to display.
     */
    protected final void dspHighlightedMsg(final String msg) {
        setAlertHighlighting();
        Util.dspmsg(msg);
    }

    /**
     * Reset highlighting to default.
     */
    protected final void resetHighlighting() {
        Alert.green("");
        setNormalHighlighting();
    }
    
    private final FontManager fm = FontManager.getInstance();

    /**
     * Check to see if we need to alert the user for input action.
     */
    protected void checkInput() {
    }

    /**
     * Is waiting for input.
     */
    private boolean isWaitingForInput = false;

    /**
     * @return True if waiting for input.
     */
    private boolean isWaitingForInput() {
        checkInput();
        return isWaitingForInput;
    }

    /**
     * @param value
     *            Value to set.
     */
    public final void setWaitingForInput(final boolean value) {
        isWaitingForInput = value;
    }

    /**
     * Border title.
     */
    private String pborderTitle;

    /**
     * @return Border title.
     */
    public final String getBorderTitle() {
        if (pborderTitle == null) {
            pborderTitle = "";
        }
        return pborderTitle;
    }

    /**
     * Normal border.
     */
    private TitledBorder normalBorder;
    /**
     * Wait border.
     */
    private TitledBorder waitBorder;
    /**
     * Alert border.
     */
    private TitledBorder alertBorder;
    /**
     * In progress border.
     */
    private TitledBorder inprogressBorder;

    /**
     * Set border title.
     *
     * @param newBorderTitle
     *            New border title.
     */
    public final void setBorderTitle(final String newBorderTitle) {
        pborderTitle = newBorderTitle;
        getNormalBorder().setTitle(pborderTitle);
        getWaitBorder().setTitle(pborderTitle);
        getAlertBorder().setTitle(pborderTitle);
        getInprogressBorder().setTitle(pborderTitle);
    }


    /**
     * @return Normal titled border.
     */
    protected final TitledBorder getNormalBorder() {
        if (isWaitingForInput()) {
            return getAlertBorder();
        }
        if (normalBorder == null) {
            LineBorder lb = new LineBorder(
                    LookAndFeel.Colors.BORDER_COLOR_NORMAL.getColor(), 1);
            normalBorder = new TitledBorder(lb, pborderTitle);
            fm.register(normalBorder, FontManager.FontType.borderTitle);
            normalBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_NORMAL
                    .getColor());
        }
        return normalBorder;
    }

    /**
     * @return Wait titled border.
     */
    protected final TitledBorder getWaitBorder() {
        if (waitBorder == null) {
            LineBorder lb = new LineBorder(LookAndFeel.Colors.BORDER_COLOR_WAIT
                    .getColor(), 1);
            waitBorder = new TitledBorder(lb, pborderTitle);
            waitBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_WAIT
                    .getColor());
            fm.register(waitBorder, FontManager.FontType.borderTitle);
        }
        return waitBorder;
    }

    /**
     * @return Alert titled border.
     */
    protected final TitledBorder getAlertBorder() {
        if (alertBorder == null) {
            LineBorder lb = new LineBorder(
                    LookAndFeel.Colors.BORDER_COLOR_ALERT.getColor(), 1);
            alertBorder = new TitledBorder(lb, pborderTitle);
            alertBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_ALERT
                    .getColor());
            fm.register(alertBorder, FontManager.FontType.borderTitle);
            setNormalHighlighting();
        }
        return alertBorder;
    }

    /**
     * @return In progress titled border.
     */
    protected final TitledBorder getInprogressBorder() {
        if (inprogressBorder == null) {
            LineBorder lb = new LineBorder(
                    LookAndFeel.Colors.BORDER_COLOR_INPROGRESS.getColor(), 1);
            inprogressBorder = new TitledBorder(lb, pborderTitle);
            inprogressBorder
                    .setTitleColor(LookAndFeel.Colors.BORDER_COLOR_INPROGRESS
                            .getColor());
            fm.register(inprogressBorder,
                    FontManager.FontType.borderTitle);
            setNormalHighlighting();
        }
        return inprogressBorder;
    }

    /**
     * Set normal highlighting for the boder title.
     */
    public final void setNormalHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getNormalBorder());
        reset();
    }

    /**
     * If you want to show something in progress, use this.
     */
    public final void setWaitHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getWaitBorder());
        reset();
    }

    /**
     * Set alert highlighting.
     */
    public final void setAlertHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getAlertBorder());
        reset();
    }

    /**
     * Set in progress highlighting.
     */
    public final void setInprogressHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getInprogressBorder());
        reset();
    }

    /**
     * Reset.
     */
    public final void reset() {
        getPanel().invalidate();
        getPanel().getParent().validate();
    }

	public void setToDefaults() {
		super.setToDefaults();
	}

}
